// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
#pragma once
#include "Forecast.h"

namespace Weathr
{
    [Windows::UI::Xaml::Data::Bindable]
    [Windows::Foundation::Metadata::WebHostHidden]
    public ref class ForecastGroup sealed : Windows::UI::Xaml::Data::INotifyPropertyChanged
    {
    public:
        virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler^ PropertyChanged;

        property Windows::Foundation::Collections::IObservableVector<Forecast^>^ Items;

        property bool HasMultipleItems
        {
            bool get()
            {
                return Items != nullptr && Items->Size > 1;
            }
        }

        property Forecast^ Current
        {
            Forecast^ get()
            {
                return m_current;
            }
            void set(Forecast^ value)
            {
                if (m_current != value)
                {
                    if (m_current != nullptr)
                    {
                        m_current->IsSelected = false;
                    }
                    if (value != nullptr)
                    {
                        value->IsSelected = true;
                    }

                    m_current = value; OnPropertyChanged("Current");
                }
            }
        }

        property bool IsVisible
        {
            bool get() { return m_visible; }
            void set(bool value)
            {
                if (value != m_visible)
                {
                    m_visible = value; OnPropertyChanged("IsVisible");
                }
            }
        }

        property int32 ScreenLocationLeft
        {
            int32 get() { return m_screenLocationLeft; }
            void set(int32 value)
            {
                if (m_screenLocationLeft != value)
                {
                    m_screenLocationLeft = value; OnPropertyChanged("ScreenLocationLeft");
                }
            }
        }

        property int32 ScreenLocationTop
        {
            int32 get() { return m_screenLocationTop; }
            void set(int32 value)
            {
                if (m_screenLocationTop != value)
                {
                    m_screenLocationTop = value; OnPropertyChanged("ScreenLocationTop");
                }
            }
        }

    internal:
        ForecastGroup() : m_visible(false)
        {
            Items = ref new Platform::Collections::Vector<Forecast^>();
            Items->VectorChanged += ref new Windows::Foundation::Collections::VectorChangedEventHandler<Forecast^>(this, &ForecastGroup::OnItemsChanged);
        }

        property Windows::Foundation::Point Center
        {
            Windows::Foundation::Point get()
            {
                int32 xsum = 0;
                int32 ysum = 0;
                for (auto forecast : Items)
                {
                    xsum += forecast->ScreenLocationLeft;
                    ysum += forecast->ScreenLocationTop;
                }
                Windows::Foundation::Point center;
                center.X = (float) xsum / Items->Size;
                center.Y = (float) ysum / Items->Size;
                return center;
            }
        }

        float ComputeRadius()
        {
            float largestDistance = 0.0f;
            std::max_element(begin(Items), end(Items), [&largestDistance](Forecast^ f1, Forecast^ f2)
            {
                if (f1 == f2)
                {
                    return false;
                }
                float dx = static_cast<float>(abs(f1->ScreenLocationLeft - f2->ScreenLocationLeft));
                float dy = static_cast<float>(abs(f1->ScreenLocationTop - f2->ScreenLocationTop));
                float distance = hypotf(dx, dy);
                if (distance > largestDistance)
                {
                    largestDistance = distance;
                    return true;
                }
                return false;
            });
            return static_cast<float>(0.5f * largestDistance);
        }

        void Append(Forecast^ forecast)
        {
            Items->Append(forecast);

            if (Items->Size == 1)
            {
                Current = forecast;
                OnPropertyChanged("Selected");
            }

            forecast->ParentGroup = this;
        }

    private:
        bool m_visible;
        Forecast^ m_current;
        int32 m_screenLocationLeft;
        int32 m_screenLocationTop;

        void OnItemsChanged(Windows::Foundation::Collections::IObservableVector<Forecast^>^ sender, Windows::Foundation::Collections::IVectorChangedEventArgs^ e)
        {
            (void) sender;
            assert(sender == Items);

            auto size = Items->Size;
            switch (e->CollectionChange)
            {
            case Windows::Foundation::Collections::CollectionChange::ItemInserted:
                if (size > 1)
                {
                    OnPropertyChanged("HasMultipleItems");
                }
                break;
            case Windows::Foundation::Collections::CollectionChange::ItemRemoved:
                if (size < 2)
                {
                    OnPropertyChanged("HasMultipleItems");
                }
            case Windows::Foundation::Collections::CollectionChange::Reset:
                OnPropertyChanged("HasMultipleItems");
                break;
            }
        }

        inline void OnPropertyChanged(Platform::String^ propertyName)
        {
            PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs(propertyName));
        }
    };
}